Skip to content
This repository was archived by the owner on Nov 22, 2024. It is now read-only.

feat(universal-cookie): basic implementation of universal cookie - #404

Merged
PatrickJS merged 1 commit into
angular:masterfrom
laskoviymishka:feature/cookie
May 18, 2016
Merged

PatrickJS merged 1 commit into
angular:masterfrom
laskoviymishka:feature/cookie

Conversation

@laskoviymishka

@laskoviymishka laskoviymishka commented May 11, 2016 •

Copy link
Copy Markdown
Contributor

Related to issues: #273, and aspnet/JavaScriptServices#66

This is pretty easy fix, just to enable possibility to integrate server request cookie

  • Please check if the PR fulfills these requirements
  • The commit message follows our guidelines: https://github.com/angular/universal/blob/master/CONTRIBUTING.md#commit-message-format
  • Tests for the changes have been added (for bug fixes / features)
  • Docs have been added / updated (for bug fixes / features)
  • What modules are related to this pull-request
  • express-engine
  • grunt-prerender
  • gulp-prerender
  • hapi-engine
  • preboot
  • universal-preview
  • universal
  • webpack-prerender
  • What kind of change does this PR introduce? (Bug fix, feature, docs update, ...)
    remove unused proxy imports from some test files
  • What is the current behavior? (You can also link to an open issue here)
    Currently cookies not handled, just abstract class provided.
  • What is the new behavior (if this is a feature change)?
    Provided abstract class injected as optional parameter to node_http, so we could grab cookie string from it. It provide abiliti to inject this cookie object from server. Here is some sample boot-server, that i use with my aspnet prerenderer:
import 'angular2-universal/polyfills';
import * as ngCore from '@angular/core';
import * as ngRouter from '@angular/router-deprecated';
import * as ngUniversal from 'angular2-universal';
import * as aspnet from 'aspnet-prerendering';
import { Cookie } from './components/shared/Cookie';
import { BASE_URL, ORIGIN_URL, REQUEST_URL, REQUEST_COOKIE } from 'angular2-universal/common';
import { App } from './components/app/app';

export default function (params: aspnet.BootFuncParams): Promise<{ html: string, globals?: any }> {
  let cookie = new Cookie(params.cookie); // params.cookie populated on aspnet server and pass to boot function
  const serverBindings = [
    ngCore.provide(BASE_URL, { useValue: '/' }),
    ngCore.provide(ORIGIN_URL, { useValue: params.origin }),
    ngCore.provide(REQUEST_URL, { useValue: params.url }),
    ngCore.provide(REQUEST_COOKIE, { useValue: cookie }), // provide cookie to ng2-universal
    ...ngUniversal.NODE_PLATFORM_PIPES,
    ...ngUniversal.NODE_ROUTER_PROVIDERS,
    ...ngUniversal.NODE_HTTP_PROVIDERS,
  ];

  let boot = ngUniversal.bootloader({
    directives: [App],
    componentProviders: serverBindings,
    async: true,
    preboot: false,
    // TODO: Render just the <app> component instead of wrapping it inside an extra HTML document
    // Waiting on https://github.com/angular/universal/issues/347
    template: '<!DOCTYPE html>\n<html><head></head><body><app></app></body></html>'
  })

  // aspnet-prerender specific code
  return boot.serializeApplication().then(html => {
    boot.dispose();
    return { html };
  });
}
  • Does this PR introduce a breaking change? (What changes might users need to make in their application due to this PR?)
    No
  • Other information:
  • add opaque token to be able inject cookie object
  • add optional request cookie object into node_http service

- add opaque token to be able inject cookie object
- add optional request cookie object into node_http service
@PatrickJS

Copy link
Copy Markdown
Contributor

pretty good. We planned on cookie being a service as Cookie

@laskoviymishka

laskoviymishka commented May 17, 2016 •

Copy link
Copy Markdown
Contributor Author

@gdi2290 well the question where implementation of such service should be placed. This PR just allow you to inject any implementation of Cookie.
Right now it assume that server render function will introduce such class and just provide it via angular DI.

So to complete Cookies feature there is 2 possible option:

  1. Leave this implementation as is - inside universal package, and modify all other packages with proper Cookie implementation. This will require implementation for cookies for every server that ng-universal will support. Just like i implemented with ASPNET server. This implementation much more flexible, since server decide everything about Cookies specific code. For example aspnet server could provide cookies as pure string, that will be injected inside of boot function as params. But node server could pass proper Cookie object. So end user code be same as in PR sample (Cookie implementation provided by aspnet package)
  2. Introduce some shared CookieService or just implement some basic Cookie class which could be populated in a server boot func. From these point we should be able to inject cookie value inside of boot function. So code become little bit different:

/*
same as example
*/

export default function (params: aspnet.BootFuncParams): Promise<{ html: string, globals?: any }> {
  let cookie = new ngUniversal.Cookie(); // create universal cookie implementation
  magicParseFunction(params.cookie).map((key, value) => cookie.set(key, value));// set cookie with some cookie contract object that need to parsed from pure aspnet cookie string

  const serverBindings = [
    ngCore.provide(BASE_URL, { useValue: '/' }),
    ngCore.provide(ORIGIN_URL, { useValue: params.origin }),
    ngCore.provide(REQUEST_URL, { useValue: params.url }),
    ngCore.provide(REQUEST_COOKIE, { useValue: cookie }), // provide cookie to ng2-universal
    ...ngUniversal.NODE_PLATFORM_PIPES,
    ...ngUniversal.NODE_ROUTER_PROVIDERS,
    ...ngUniversal.NODE_HTTP_PROVIDERS,
  ];
/*
same as example
*/

Both of these option still need to inject Cookie object, so we can start from these PR, and later decide which way should it be implemented.

@PatrickJS

Copy link
Copy Markdown
Contributor

@laskoviymishka I can add this just for now if you need it sooner than later. Later I'll create a cookie service that would be the prefer method. If that works for you then I can merge it

@laskoviymishka

laskoviymishka commented May 17, 2016 •

Copy link
Copy Markdown
Contributor Author

@gdi2290 this would be really great! Later, when cookie service will be created, i'll refactor my code and adjust it to prefered method, but for now these would work good at least for me 😅 .

@PatrickJS
PatrickJS merged commit e018ece into angular:master May 18, 2016
@kuldeepkeshwar

Copy link
Copy Markdown

@gdi2290 @laskoviymishka
is the implementation completed , if so can you please share an example showing how to read/write cookies.

@laskoviymishka

Copy link
Copy Markdown
Contributor Author

Implementation still not completed, but you can see how it could work in PR sample

@veliancreate-zz

veliancreate-zz commented Aug 4, 2016 •

Copy link
Copy Markdown

@laskoviymishka @gdi2290

Hi guys, we have been unable to implement cookies as yet. When we pass the COOKIE_KEY and COOKIE values through the providers on ExpressEngineConfig, both are undefined in dist/node/node_http.js. ORIGIN_URL and BASE_URL are however defined as expected.

Following from the Angular2 Universal Starter repo, our main.node.ts file looks like this:



// Angular 2 Universal
import {
  REQUEST_URL,
  ORIGIN_URL,
  Cookie,
  CookieAttributes,
  COOKIE_KEY,
  NODE_LOCATION_PROVIDERS,
  NODE_HTTP_PROVIDERS,
  ExpressEngineConfig,
} from 'angular2-universal';

import {Injectable} from "@angular/core";
import { APP_BASE_HREF} from '@angular/common';

// Application
import {ElaraApp} from './app/app';
import {appRouterProviders} from './app/routes/app.routes';
import {SessionService, ServerSessionService} from './app/services/sessions.service';
import {WindowService} from './app/services/window.service';
import {AppsService} from './app/services/apps.service';
import {AuthService} from './app/services/auth.service';
import {UserService} from './app/services/user.service';
import {AuthServerService} from './app/services/authServer.service';
import {RedirectService, RedirectServerService} from './app/services/redirect.service';
import {AuthGuard} from './app/services/guard/auth-guard.service';
import {NotificationService} from './app/services/notification.service';
import {ModalService} from './app/services/modal.service';
import {ExtendedInfoService} from './app/services/extended-info.service';

@Injectable()
class BasicCookie implements Cookie {
  constructor(private headers: any){
  }
  set(key: string, value: string, attributes?: CookieAttributes): void{
    this.headers[key] = value;
  }
  get(key?: string): string {
    if(this.headers[key]){
      return key + '=' + this.headers[key];
    }
    return "";  
  }
  remove(key: string, attributes?: CookieAttributes): any{
    return false;
  }
  toJSON(): Object{
    return JSON.stringify(this.headers);
  }
}

export function ngApp(req, res) {
  let baseUrl = '/';
  let url = req.originalUrl || '/';
  let originUrl = process.env.WEB_URL || 'http://locahost:5000';
  let cookie = new BasicCookie(req.cookies);
  if(req.query.jwt) {
    cookie.set("my_session", req.query.jwt);
    let now = new Date(Date.now());
    res.cookie("my_session", req.query.jwt, {expires: new Date(now.setHours(now.getHours() + 1)), httpOnly: false});
  }

  if(cookie.get('my_session')){
      let config: ExpressEngineConfig = {
          directives: [
            MyApp
          ],
          platformProviders: [
            {provide: ORIGIN_URL, useValue: originUrl},
            {provide: APP_BASE_HREF, useValue: baseUrl},
            {provide: COOKIE_KEY, useValue: 'my_session'}
          ],
          providers: [
            NODE_HTTP_PROVIDERS,
            appRouterProviders,
            NODE_LOCATION_PROVIDERS,
            {provide: Cookie, useValue: cookie},
            AppsService,
            WindowService,
            NotificationService,
            ExtendedInfoService,
            {provide: SessionService, useClass: ServerSessionService},
            AuthGuard,
            UserService,
            ModalService,
            {provide: AuthService, useClass: AuthServerService},
            {provide: RedirectService, useClass: RedirectServerService},
            {provide: REQUEST_URL, useValue: url},
          ],
          async: true,
          preboot: false // { appRoot: 'app' } // your top level app component selector
      };

    return res.render('index', config);  
  }

  return res.redirect('https://portal.my.io?redirect=https://' + req.get('Host') + req.originalUrl)

}

Any ideas?

@veliancreate-zz

Copy link
Copy Markdown

Ok so it looks like these changes fixes the issue in src/node/node_http.ts

line 65:

if (cookieValue && !req.headers.get('Cookie')) {
   req.headers.append('Cookie', cookieValue);
 }

and

@Injectable()
export class NodeBackend implements ConnectionBackend {
  constructor(
    private _baseResponseOptions: ResponseOptions,
    private _ngZone: NgZone,
    @Inject(BASE_URL) private _baseUrl: string,
    @Inject(ORIGIN_URL) private _originUrl: string,
    @Inject(Cookie) private _cookie: Cookie,
    @Inject(COOKIE_KEY) private _cookieKey: Object) {}

  public createConnection(request: Request): NodeConnection {
    return new NodeConnection(request, this._baseResponseOptions, this._ngZone, this._baseUrl, this._originUrl, this._cookie, this._cookieKey);
  }
}

I can make a PR to that effect if it is of assistance?

@PatrickJS

Copy link
Copy Markdown
Contributor

@veliancreate can you make a PR

@xzengCB xzengCB left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see this in the ng2 universal

@angular-automatic-lock-bot

Copy link
Copy Markdown

This issue has been automatically locked due to inactivity.
Please file a new issue if you are encountering a similar or related problem.

Read more about our automatic conversation locking policy.

This action has been performed automatically by a bot.

@angular-automatic-lock-bot angular-automatic-lock-bot Bot locked and limited conversation to collaborators Sep 5, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants